/**ChPinyomiScorer.java
 *
 * Description:
 * Pinyomi Scorer
 *
 * Anping Zhou <anping.zhou@gmail.com>
 * Created: Sep 16, 2007
 */
package jp.ac.utokyo.pinyomi;

import java.io.IOException;

public class ChPinyomiScorer {
	private final static int QITYPE_UNKNOWN = 0;
	private final static int QITYPE_STROKE = 1;
	private final static int QITYPE_PINYIN = 2;
	private final static int QITYPE_NOTRANSFORM = 3;
	private final static int QITYPE_ASIANCHARTRANSFORM = 4;
	private final static int QITYPE_HIRAGANA = 5;
	private final static int QITYPE_WILDCARD = 6;
	private final static int QITYPE_STROKENUM = 7;
	
	/**
	 * Caculate P(w|q) ->  P(w) * \prod P(q_i | w_i)
	 * @param queries Array of String.
	 * @param word Target word.
	 * @return
	 * @throws IOException 
	 */
	public static double caclLogProb(String[] queries, String word) throws IOException{
		double logprob = 0;
		
		logprob += wordLogProb(word);
		
		for(int i = 0; i< queries.length; i++){
			logprob += charLogProb(queries[i],word.charAt(i));
		}
		
		return logprob;
	}
	
	private static double charLogProb(String qi, char wi) throws IOException{
//		double logprob = Settings.nullLogProb;
		double logprob = -1000;
		switch (qiType(qi, wi)) {
		case QITYPE_STROKE:
		case QITYPE_NOTRANSFORM:
		case QITYPE_STROKENUM:
		case QITYPE_WILDCARD:
			logprob = 0;
			break;
		case QITYPE_PINYIN:
			logprob = caclPinyinProb(qi, wi);
			break;
		case QITYPE_ASIANCHARTRANSFORM:
			logprob = caclTransProb(qi,wi);
			break;
		case QITYPE_HIRAGANA:
			logprob = caclReadingLogProb(qi,wi);
			break;
		case QITYPE_UNKNOWN:
		default:
		}
		
		return logprob;
	}
	
	private static double wordLogProb(String word) throws IOException{
		WordProbTable t = WordProbTable.getInstance(Settings.ChWordCorpusProbs);
		return t.getLogProb(word);
	}
	
	private static double caclReadingLogProb(String qi, char wi) throws IOException {
		Hanzi2KanjiTable hanzi2Kanji = Hanzi2KanjiTable.getInstance();
		KanjiReadingTable KanjiReading = KanjiReadingTable.getInstance();

        double prob = 0.0;
        Pair kanjis = hanzi2Kanji.getMapVal(String.valueOf(wi));
        for (int i = 0; i < kanjis.size(); i++) {
            // So far, constrained to cognate mapping
            // TODO: Next Version - get rid off the cognate constraint
            if (!kanjis.getTag(i).equals("C")) 
                continue;

            Pair readings = KanjiReading.getMapVal(kanjis.getKey(i));  
            if (readings != null)
            	prob += kanjis.getProb(i) * readings.getProb(qi);
        }

		if(String.valueOf(wi).equals("哭")) System.out.println("Ku prob is "+prob);

        if (prob == 0.0)
            return Settings.nullLogProb; 
        else
            return Math.log(prob);
	}

	private static double caclTransProb(String qi, char wi) throws IOException {
		Hanzi2KanjiTable t = Hanzi2KanjiTable.getInstance();
		return t.getLogProb(String.valueOf(wi), qi);
	}

	private static double caclPinyinProb(String qi, char wi) throws IOException {
		PinyinTable t = PinyinTable.getInstance();
		return t.getLogProb(String.valueOf(wi), qi);
	}

	private static int qiType(String qi,char wi) throws IOException{
		int type=QITYPE_UNKNOWN;
		
		if ("?".equals(qi)){
			type = QITYPE_WILDCARD;
		}else if (isStroke(qi)){
			type = QITYPE_STROKE;
		}else if (isStrokeNum(qi)){
			type = QITYPE_STROKENUM;
		} else if(isPinyin(qi)){
			type = QITYPE_PINYIN;
		} else if(noTransform(qi, wi)){
			type = QITYPE_NOTRANSFORM;
		} else if(isHanzi2Kanji(qi, wi)){
			type = QITYPE_ASIANCHARTRANSFORM;
		} else if(isHiragana(qi)){
			type = QITYPE_HIRAGANA;
		}
		return type;
	}
	
	private static boolean isStrokeNum(String qi){
		return qi.matches("[0-9]+");
	}
	
	private static boolean isStroke(String qi){
		return qi.matches("[h|v|l|r|o]+");
	}
	
	// This is just a simple check. Can not guarantee whether it is really a pinyin or not.
	private static boolean isPinyin(String qi){
		return qi.matches("[a-z]+");
	}
	
	private static boolean noTransform(String qi, char wi){
		return (qi.length()==1 && qi.charAt(0)== wi);
	}
	
	private static boolean isHanzi2Kanji(String qi, char wi) throws IOException{
		Hanzi2KanjiTable t = Hanzi2KanjiTable.getInstance();
		return t.hasRoute(String.valueOf(wi), qi);
	}
	
	private static boolean isHiragana(String qi){
		for (int i = 0; i < qi.length(); i++) {
			char c = qi.charAt(i);
			if (!(c>='ぁ' && c<='ん')) return false;
		}
		return true;
	}
	

}
